Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Improve navbar compatiblity for Bootstrap 5 and light/dark modes #1145

Merged
merged 16 commits into from
Jan 22, 2025

Conversation

gadenbuie
Copy link
Member

@gadenbuie gadenbuie commented Dec 3, 2024

This PR is a second third take at #1135, and now the second part of a two-part PR. #1146 covers the markup and this PR covers the Sass changes.

There are a few things happening in the two PRs. The primary goal is to bring bslib in line with Bootstrap 5's expectations around how the navbar background color is controlled, while adding appropriate controls for the following scenarios:

  1. By default a navbar that follows the current light/dark color mode.
  2. Globally set the navbar backround for both light/dark mode with $navbar-bg.
  3. Individually set light and dark navbar backgrounds with $navbar-light-bg and $navbar-dark-bg.
  4. Individually set the background color of a navbar with navbar_options(bg = "...").
  5. Individually set the background of a navbar with BS 5 markup, e.g. navbar_options(class = "bg-primary", type = "dark").

In general, for most BS 5+ users, I'd recommend using the last two options.

1. Navbar background follows light/dark color mode

library(shiny)
pkgload::load_all()
shiny::devmode(TRUE)

VERSION <- 5

ui <- page_navbar(
  title = "My Simple App",
  theme = bs_theme(
    preset = "shiny",
    version = VERSION,
  ),
  nav_panel(
    "Home",
    h2("Welcome to the Home Page"),
    if (VERSION >= 5) {
      bslib::input_dark_mode()
    }
  ),
  nav_panel(
    "About",
    h2("About navbars")
  )
)

server <- function(input, output, session) {

}

shinyApp(ui, server)

2. Globally fix navbar colors, regardless of color mode

library(shiny)
pkgload::load_all()
shiny::devmode(TRUE)

VERSION <- 5

ui <- page_navbar(
  title = "My Simple App",
  theme = bs_theme(
    preset = "shiny",
    version = VERSION,
    navbar_bg = "#732400",
  ),
  nav_panel(
    "Home",
    h2("Welcome to the Home Page"),
    if (VERSION >= 5) {
      bslib::input_dark_mode()
    }
  ),
  nav_panel(
    "About",
    h2("About navbars")
  )
)

server <- function(input, output, session) {

}

shinyApp(ui, server)

3. Individually choose navbar colors in light/dark mode

library(shiny)
pkgload::load_all()
shiny::devmode(TRUE)

VERSION <- 5

ui <- page_navbar(
  title = "My Simple App",
  theme = bs_theme(
    preset = "shiny",
    version = VERSION,
    navbar_light_bg = "#b2d8ff",
    navbar_dark_bg = "#00165d",
  ),
  nav_panel(
    "Home",
    h2("Welcome to the Home Page"),
    if (VERSION >= 5) {
      bslib::input_dark_mode()
    }
  ),
  nav_panel(
    "About",
    h2("About navbars")
  )
)

server <- function(input, output, session) {

}

shinyApp(ui, server)

4. Locally set navbar colors using navbar_options(bg=)

library(shiny)
pkgload::load_all()
shiny::devmode(TRUE)

VERSION <- 5

ui <- page_navbar(
  title = "My Simple App",
  theme = bs_theme(
    preset = "shiny",
    version = VERSION,
  ),
  navbar_options = navbar_options(bg = "#732400"),
  nav_panel(
    "Home",
    h2("Welcome to the Home Page"),
    if (VERSION >= 5) {
      bslib::input_dark_mode()
    }
  ),
  nav_panel(
    "About",
    h2("About navbars")
  )
)

server <- function(input, output, session) {

}

shinyApp(ui, server)

5. Locally set navbar colors using BS 5's recommended approach

library(shiny)
pkgload::load_all()
shiny::devmode(TRUE)

VERSION <- 5

ui <- page_navbar(
  title = "My Simple App",
  theme = bs_theme(
    preset = "shiny",
    version = VERSION,
  ),
  navbar_options = navbar_options(
    class = "bg-primary",
    type = "dark"
  ),
  nav_panel(
    "Home",
    h2("Welcome to the Home Page"),
    if (VERSION >= 5) {
      bslib::input_dark_mode()
    }
  ),
  nav_panel(
    "About",
    h2("About navbars")
  )
)

server <- function(input, output, session) {

}

shinyApp(ui, server)

Notes

Following bs-theme color mode by default

Bootstrap 5 primarily wants to have stable navbar colors, but we both -- bslib and pkgdown -- independently developed an approach where the navbar changes colors in light and dark mode. I've patched the BS 5 navbars Sass files to accommodate this.

The biggest source of added complexity in this change is that both [data-bs-theme="dark"] .navbar and [data-bs-theme="light"] .navbar[data-bs-theme="dark"] should result in a dark navbar style, but [data-bs-theme="light"] .navbar.bg-primary[data-bs-theme="dark"] should be a dark navbar (i.e. light text) with a primary-colored background.

These three scenarios required careful construction of selectors, rule ordering, and selector specificity management. In other words, it's why we use :where() and separately define [data-bs-theme="light"] .navbar and .navbar[data-bs-theme="light"].

Localized >>> global changes

Setting $navbar-bg globally changes both light and dark themes, and for all navbars. It's convenient but introduces a downside that the data-bs-theme attribute on the .navbar loses meaning.

For the same reason, users will want to use light colors (that result in black contrast text) for $navbar-light-bg and dark colors (that result in white contrast text) for $navbar-dark-bg.

New CSS variables, old classes

The old .navbar-default and .navbar-inverse classe are maintained for BS 4 compatibility with BS 3 styles. They are now empty classes for BS 5, but still included in the markup in case there are users who rely on them. (They should probably transition away from that, though.)

We also still use --bslib-navbar-default-bg and --bslib-navbar-inverse-bg CSS variables, but I've added --bslib-navbar-light-bg and --bslib-navbar-dark-bg in front of both variables so that they can be set client-side without Sass.

This rule only changes the background color of the navbar,
which is not enough to fully restyle the navbar in dark mode.
It might work in the default cases, but it certainly does not
work if users have set $navbar-dark-bg or $navbar-light-bg
to appropriate values. Note that Bootstrap expects the navbar
colors to be static (i.e. the same in light and dark mode), so if
we want to support different navbar colors we'll need to
implement something better.
Bootstrap has the navbar toggler icon follow the global color mode, which makes the icon invisible when placed on a light background in dark mode. Outside of this rule, Bootstrap expects the navbar color to be consistent in light and dark mode.
…ty possible

Otherwise they get in the way of local classes, e.g. `bg-blue` or `bg-primary`,
which are the primary mechanism for setting navbar color in BS5

https://getbootstrap.com/docs/5.3/components/navbar/#color-schemes
@gadenbuie gadenbuie force-pushed the feat/bs5-navbar-bg-dark-light branch from ed14acf to fd2e808 Compare December 4, 2024 15:42
@gadenbuie gadenbuie changed the base branch from main to feat/navbar-options-bs5 December 4, 2024 15:42
@cpsievert
Copy link
Collaborator

Before I dive into this, I just did a quick run of these examples with main, and it seems 1-3 currently work the way we want them to? I can see though that, for 4, the navbar color doesn't change depending on the color mode.

@gadenbuie
Copy link
Member Author

Before I dive into this, I just did a quick run of these examples with main, and it seems 1-3 currently work the way we want them to?

The first option only works in the Shiny preset and it works in a way that it breaks the second option. #1135 shows the problematic behavior.

@gadenbuie gadenbuie merged commit e0ce81d into feat/navbar-options-bs5 Jan 22, 2025
1 check passed
@gadenbuie gadenbuie deleted the feat/bs5-navbar-bg-dark-light branch January 22, 2025 17:34
gadenbuie added a commit that referenced this pull request Jan 22, 2025
* fix: apply `data-bs-theme="dark"` to `<nav>` when `inverse = TRUE`

* feat(navbar): Set `data-bs-theme` from `inverse`

Lets `inverse` be a character value that is used directly for `data-bs-theme`.
Turns out this is a backwards compatible change that opens the door
to the future addition of another argument.

* chore: explicitly cast to character

Co-authored-by: Carson Sievert <[email protected]>

* feat: introduce `type` and `attrs` (via `...`) in `navbar_options()`

* refactor: Move `navbar_options()` to its own R file

* tests: Update `navbar_options()` tests

* fixup: small details in `navbar_options()`

* tests: Add another inverse -> type test

* refactor: Use faster color contrast getter

* feat: Apply `...` from `navbar_options()` as attributes on the navbar container

Fixes #940

* feat: Warn if users try `navbar_options(inverse=)` instead of using `type`

* chore: Add note about what to do if precompiled theme output fails

* fix(navbar_options): Require all named arguments in `...` and use `attribs` for consistency

* docs(navbar_options): Add note about `inverse` -> `type` to docs

* chore: revert moving `navbar_options()` for better diff

* chore: Apply suggestions from code review

* `devtools::document()` (GitHub Actions)

* chore: code style

* refactor: Use `navbar_options` inside `navs_bar_()`

Allows us to avoid needing to do surgery on the navbar later

* tests(navs_bar_): Add snapshots to track navbar markup

* rename: `theme` instead of `type`

* `devtools::document()` (GitHub Actions)

* fix: update `type` -> `theme`

* feat: Improve navbar compatiblity for Bootstrap 5 and light/dark modes (#1145)

* fix(navbar): Don't flip navbar bg in dark mode

This rule only changes the background color of the navbar,
which is not enough to fully restyle the navbar in dark mode.
It might work in the default cases, but it certainly does not
work if users have set $navbar-dark-bg or $navbar-light-bg
to appropriate values. Note that Bootstrap expects the navbar
colors to be static (i.e. the same in light and dark mode), so if
we want to support different navbar colors we'll need to
implement something better.

* fix(bootstrap): Navbar toggler icon should follow navbar color mode

Bootstrap has the navbar toggler icon follow the global color mode, which makes the icon invisible when placed on a light background in dark mode. Outside of this rule, Bootstrap expects the navbar color to be consistent in light and dark mode.

* fix(bootstrap): Keep global color mode follow

* fix: Fix `_navbar.scss` patch

* feat: Only use `.navbar-default` and `.navbar-inverse` classes in BS <5

* fix(navbar_compat): navbar light background

* feat: account for navbar in light mode region

* feat: use `--bslib-navbar-{light,dark}-bg` variables

* feat(shiny-preset): Use border-bottom for default navbar not in a dashboard page

* refactor(shiny-preset): Use Sass vars to set navbar light/dark bg

* fix(bs5): Selector on light-region navbar-toggler-icon

* fix(navbar): Dark/light adjustments need to have the lowest specificity possible

Otherwise they get in the way of local classes, e.g. `bg-blue` or `bg-primary`,
which are the primary mechanism for setting navbar color in BS5

https://getbootstrap.com/docs/5.3/components/navbar/#color-schemes

* fix(navbar): Use `:where()` to reduce navbar dark/light styles to minimal specificity

* fix(navbar): Use `:where()` when setting navbar bg to ensure that utility classes will win

* feat!(navbars): Don't use BS3 compat for navbars in BS5+

* chore: whitespace fixes

* Resave distributed files (GitHub Action)

* Resave distributed files (GitHub Action)

* docs: Add NEWS item

---------

Co-authored-by: Carson Sievert <[email protected]>
Co-authored-by: gadenbuie <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants